Feat: Cadastrar, Renomear e Remover tipos de vegetações - #525
JosueModesto wants to merge 5 commits into
Conversation
|
|
||
| return [ | ||
| { | ||
| handlers: [ |
There was a problem hiding this comment.
POST, PUT e DELETE montam só o controller em handlers. O legado POST /vegetacoes exige tokensMiddleware([CURADOR, OPERADOR]). País/estado v2 são só GET públicos e não justificam mutação anônima do catálogo. Os testes de escrita passam sem Authorization.
| } | ||
| }) | ||
|
|
||
| test('retorna 404 para id inexistente', async () => { |
There was a problem hiding this comment.
O PR pede nome vazio → 400, duplicidade → 409, vegetacaoId inválido → 400 e 404. Este arquivo só cobre sucesso, 404 e id abc. DELETE só cobre 204 e 409 em uso. No PUT, nome duplicado vira BadRequestError 400, não 409.
| return Either.left(new CollectionError({ message: cause.message, cause })) | ||
| } | ||
| } | ||
|
|
There was a problem hiding this comment.
Unicidade é findByNome e depois insert/update. A tabela vegetacoes só tem PK, então duas requisições concorrentes com o mesmo nome passam no select e as duas gravam. O catch de unique/23505 não dispara sem constraint.
| updated_at timestamp with time zone DEFAULT CURRENT_TIMESTAMP NOT NULL | ||
| ); | ||
|
|
||
| CREATE UNIQUE INDEX vegetacoes_nome_unique |
There was a problem hiding this comment.
O índice único em LOWER(nome) existe só no schema de integração. Não há migration em src/database e o model Sequelize de vegetacoes.nome não é unique. Em MySQL de produção o check-then-write continua sujeito a corrida e o 23505 do adapter não dispara.
| const message = typeof error === 'object' && error !== null && 'message' in error ? String((error as { message?: unknown }).message) : '' | ||
| const constraint = typeof error === 'object' && error !== null && 'constraint' in error ? String((error as { constraint?: unknown }).constraint) : '' | ||
|
|
||
| return code === '23505' |
There was a problem hiding this comment.
Unique e FK estão mapeados com códigos/textos Postgres (23505, 23503, violates foreign key constraint). O app default é MySQL (ER_DUP_ENTRY 1062, ER_ROW_IS_REFERENCED_2 1451, foreign key constraint fails). Delete em uso no MySQL pode virar 500 em vez de 409 se error.constraint não vier preenchido.
|
|
||
| if (!authorization || typeof authorization !== 'string' || !authorization.startsWith('Bearer ')) { | ||
| return new ForbiddenError({ message: 'Token de autenticação obrigatório' }) | ||
| } |
There was a problem hiding this comment.
Token ausente ou vazio retorna 403, papel diferente de 1|2 retorna 403, expirado ou inválido retorna 401. Os testes de POST/PUT/DELETE só enviam token de curador no caminho feliz; esses ramos novos não estão cobertos.
|
|
||
| const ALLOWED_TIPOS_USUARIOS = new Set([1, 2]) | ||
|
|
||
| export class RequireVegetacaoWriteAccess implements RequestHandler { |
There was a problem hiding this comment.
RequireVegetacaoWriteAccess está no infinitivo inglês. Tipos novos devem usar 3ª pessoa do singular (RequiresVegetacaoWriteAccess) ou um verbo finito em português, sem misturar idiomas no nome.
| } | ||
|
|
||
| const cause = error instanceof Error ? error : new Error(String(error)) | ||
| return Either.left(new CollectionError({ message: cause.message, cause })) |
There was a problem hiding this comment.
O catch genérico devolve cause.message. Essa string chega no InternalServerError do controller e pode expor SQL no JSON de 500.
|
|
||
| const ALLOWED_TIPOS_USUARIOS = new Set([1, 2]) | ||
|
|
||
| export class ExigePermissaoEscritaVegetacao implements RequestHandler { |
There was a problem hiding this comment.
O arquivo RequerAcessoEscritaVegetacao.ts exporta ExigePermissaoEscritaVegetacao. O nome do arquivo deve coincidir com o tipo exportado: renomear para ExigePermissaoEscritaVegetacao.ts e ajustar o import em index.ts.
| async handle(request: HttpRequest, next: NextHandler): Promise<HttpResponse | HttpError> { | ||
| const authorization = request.headers.Authorization ?? request.headers.authorization | ||
|
|
||
| if (!authorization || typeof authorization !== 'string' || !authorization.startsWith('Bearer ')) { |
There was a problem hiding this comment.
Token ausente ou vazio retorna 403, papel diferente de 1|2 retorna 403, expirado ou inválido retorna 401. Os testes de escrita cobrem o happy path e JWT_SECRET ausente; esses ramos ainda não estão cobertos.
| } | ||
| }) | ||
|
|
||
| test('retorna 404 para id inexistente', async () => { |
There was a problem hiding this comment.
Ainda faltam PUT com nome vazio (400) e DELETE com vegetacaoId inválido (400) e inexistente (404). Este arquivo cobre sucesso, 404, id inválido e duplicidade; remove-vegetacoes.test.ts só cobre 204 e 409 em uso.
Close #490
O que foi feito
Foi implementado o módulo de cadastro, atualização e remoção de tipos de vegetação na API v2, preservando a API legada sem alterações e seguindo o padrão de autenticação já utilizado pelo projeto.
Alterações principais
Cobertura de testes